/* This module implements the delay functionality and manages the delayed array */

#include "delay.h"

/* this array contains pointers on the delayed processes */
static PCB* delayed[NUMBER_MAX_PROCESSES];

/* counts the number of delayed processes. It allows us to avoid having to go through the whole array for each timer interrupt */
static uint32_t count_delayed = 0;

/* inserts pcb into the delayed array */
uint32_t insert_delayed(PCB* pcb){
  int32_t i;
  for(i=0; i < NUMBER_MAX_PROCESSES && delayed[i] != NULL; i++);
  /* either the delayed array is full or we stopped on a free place */
  if(i == NUMBER_MAX_PROCESSES)
    // the array is full (this is normally not possible)
    return 0;
  // we stopped on a free place
  delayed[i] = pcb;
  // one more delayed process 
  count_delayed ++;
  return 1;
}

/* checks if any delayed process is to be waken up */
void process_delayed(){
  int32_t i;
  int32_t j = 0;
  int32_t k = count_delayed;
  PCB* pcb;
  for(i=0; i < NUMBER_MAX_PROCESSES && j < count_delayed ; i++){
    pcb = delayed[i];
    if(pcb != NULL){
      // one of the delayed process has been found
      j ++;
      // the remaining time for this process is the time that was remaining one time quantum earlier minus the duration of a time quantum 
      int remaining = pcb_get_delay(pcb) - TIME_QUANTUM_IN_MS;
      if(remaining <= 0){ 
	// this process needs to be waken up
	pcb_set_state(pcb, READY_STATE);
	insert_ready_queue(pcb);
	delayed[i] = NULL;
	// one less delayed process
	k --;
      }else
	pcb_set_delay(pcb, remaining);
    }
  }
  count_delayed = k; 
}

/* removes the PCB pcb from the delayed array. Returns 1 if success, 0 otherwise */
int32_t remove_delayed(PCB* pcb){
  int32_t i;
  int32_t j = 0;
  PCB* pcb_delayed;
  for(i=0; i < NUMBER_MAX_PROCESSES && j < count_delayed; i++){
    pcb_delayed = delayed[i];
    if(pcb_delayed != NULL){
      j ++; //delayed process found
      if(pcb_get_pid(pcb_delayed) == pcb_get_pid(pcb)){
	//we found what we were looking for
	count_delayed --;
	delayed[i] = NULL;
	return 1;
      }
    }
  }
  return 0;
}
